//AbstractFX
//Created 01/06/13
//Created By Daniel Bowler
//
//We will be using the effect framework in this demo application. As I am
//not a huge fan of the system in place throughout the book, I am designing
//my own shader/effect management and encapsulation system. 
//
//This class will be inherited by every shader/effect that this engine uses. 
//
//NOTE: You will get a "Bad Alloc" error if you pass the wrong filename in to this
//classes constructor. Use an initilisation list to call the base classes
//constructor in your subclasses. 
//
//NOTE 2: Your subclasses need to: 1) Use the base classes constructor to init
//the effect pointer (As above, use an initilisation list in the subclasses
//constructor) 2) Init the InputLayout pointer - you should provide
//a custom vertex struct in your shader class.3) Create poiners 
//(and functions) for your shader variables - How you do this one is up to you.
//You could, for example, have just the pointers, or a setter per pointer, or a
//setter per cbuffer or even have a struct (with your effect variable pointers
//that matches each cbuffer in an effect and use that to update the data.
//4) Make the ShaderManager a friend of your subclass 5) Create a new instance
//in the ShaderManager classes InitAllShaders function. 6) (optional) set
//the initial activeTechnique to whatever you want - either in the subclasses
//constructor or via a function call perhaps when you initially create the effect object.
//By default, this will beset to the first technique in the effect file. 
//
//PositionColourShader.h/.cpp shows a simple example of the steps needed.(we have
//one technique and one variable.
//
//NOTE 3: See AbstractFX contructor for a reminder on how to set up Build time
//compliation of our shaders/effects files. 
//
//NOTE 4: Compiled fx files are .fxo - the .fx files are the files you edit.
//
//Modified: 01/06/13 - 02/06/13 - Modified the structure so that the 
//base class will create all the required techniques. The user can then set
//the active technique (by string or index) that they can use. Any calls
//to ReturnTechnique (or TechniqueDesc, etc) will return the correct data based
//on which technique is active. This greatly reduces the complexity of the subclass should
//the .fx file has multiple techniques. 
//
//Initial set activeTechnique will be the top most technique in the effect file.

#pragma once

#include <d3dx11.h>
#include "d3dx11Effect.h"
#include "d3dUtil.h"
#include "GraphicsManager.h"

#include <string>
#include <vector>

//Typedefs to make things easier - optional. 
typedef struct ID3DX11EffectTechnique Technique;
typedef struct ID3DX11Effect Effect;
typedef struct ID3D11InputLayout InputLayout;
typedef struct ID3DX11EffectPass Pass;
typedef struct _D3DX11_PASS_DESC PassDescription;
typedef struct _D3DX11_TECHNIQUE_DESC TechniqueDescription;
typedef struct _D3DX11_EFFECT_DESC EffectDescription;

//Typedef the effect variables aswell
typedef struct ID3DX11EffectVariable EffectRawVariable; //Our custom data that requires raw data transfer.
typedef struct ID3DX11EffectMatrixVariable EffectMatrixVariable;
typedef struct ID3DX11EffectVectorVariable EffectVectorVariable;
typedef struct ID3DX11EffectShaderResourceVariable EffectShaderResourceVariable; //Eg, texture maps
typedef struct ID3DX11EffectScalarVariable EffectScalarVariable; //Eg floats
typedef struct ID3DX11EffectUnorderedAccessVariable UnorderedAccessVariable;
typedef struct ID3DX11EffectUnorderedAccessViewVariable UnorderedAccessViewVariable;

//Forward declare ShaderManager so that all the subclasses are aware of it
//when they need to declare the ShaderManager as a friend.
class ShaderManager;

class AbstractFX
{
private:
	//Structure to hold data for each technique in a given effect (file)
	struct TechniqueData
	{
		TechniqueData()
		{
			tech = NULL;
			noOfPasses = 0;
			passDescArray = NULL;
		}
		~TechniqueData()
		{	
			delete []passDescArray;
			passDescArray = NULL;
		}

		//Technique pointer
		ID3DX11EffectTechnique* tech;
		//Technique description structure
		D3DX11_TECHNIQUE_DESC techDesc;
		//Technique name.
		LPCSTR techniqueName;
		//Unsigned integer holding the numebr of passes
		//for this technique.
		unsigned noOfPasses;
		//A pass description struct - one per pass (Its an example of a dynamically
		//created array). 
		D3DX11_PASS_DESC* passDescArray;
	};

public:
	//Returns the effect pointer. 
	ID3DX11Effect* ReturnEffect(){return effect;};
	//Effect description - useful if you need to access
	//the number of techniques in this effect
	D3DX11_EFFECT_DESC ReturnEffectDesc(){return effectDesc;};
	//Return inputLayout pointer. Remember this needs
	//initilizing in the subclass. You bind this pointer
	//to the IA (Input Assembler stage) before rendering.
	ID3D11InputLayout* ReturnInputLayout(){return inputLayout;};
	//Returns the current active technique data structure.
	TechniqueData* ReturnActiveTechniqueData(){return activeTechniqueData;};
	//Returns individual components of the active TechniqueData struct
	ID3DX11EffectTechnique* ReturnActiveTechnique(){return activeTechniqueData->tech;};
	D3DX11_TECHNIQUE_DESC   ReturnActiveTechniqueDesc(){return activeTechniqueData->techDesc;};
	LPCSTR					ReturnActiveTechniqueName(){return activeTechniqueData->techniqueName;};
	//Use the next two functions together (eg: D3DX11_PASS_DESC* d = shader->ReturnActive...PassDescArray())
	//										   d[shader->ReturnActive....NumberOfPasses()].....
	//To access data for a specific pass. 
	unsigned				ReturnActiveTechniqueNumberOfPasses(){return activeTechniqueData->noOfPasses;};
	D3DX11_PASS_DESC*       ReturnActiveTechniquePassDescArray(){return activeTechniqueData->passDescArray;};
	ID3DX11EffectPass*		ReturnActiveTechniquePassPointer(unsigned index);

	//Function that applies the active technique for a given pass.
	void ApplyActiveTechniqueForPass(unsigned p, ID3D11DeviceContext* context);

public:
	//Functions to set the current active technique
	void SetActiveTechniqueByName(LPCSTR techniqueName);
	void SetActiveTechniqueByIndex(unsigned index);

protected:
	//We will call the constructor explicitly in our subclasses via an initilisation
	//list. 
	AbstractFX(ID3D11Device* device, const std::wstring& filename);
	//Abstract class will handle Releasing the effect and inputLayout pointers.
	virtual ~AbstractFX() = 0;

	//Override these functions - and call them in the subclasses constructor
	//to correctly init a shader.
	virtual void InitInputLayout(ID3D11Device* device) = 0;
	virtual void InitShaderVariablePointers() = 0;

protected:
	//Effect pointers and related things that all effects/shaders share. 
	//Our effect pointer. 
	ID3DX11Effect* effect;
	//Effect description
	D3DX11_EFFECT_DESC effectDesc;

	//Input layout pointer - your subclass is responsable for creating this.
	//Though the base class will release it. 
	ID3D11InputLayout* inputLayout;

	//Techniques - We will have a vector of TechniqueData structs. Each representing
	//a single technique and the x number of passes they hold. 
	std::vector<TechniqueData*>techniqueArray;
	//Active technique data (our custom structure). I have provided getter functions
	//to return this pointer aswell as the data inside the struct. 
	TechniqueData* activeTechniqueData;

protected:
	//Other helpful functions - you dont need to use them but they could
	//be useful. They mimic the D3D11 stuff, but look a little less scarey
	//for us noobs :)
	//
	//Creates input layout for passed in inputlayout pointer, input layout desc,
	//number of inputs, a pass description. We also need the device
	void CreateInputLayout(ID3D11Device* device, 
						   const D3D11_INPUT_ELEMENT_DESC* inputLayoutDesc,
						   unsigned noOfElements);
private:
	//Disable copy constructor and assignment operator.
	AbstractFX(const AbstractFX& other);
	AbstractFX& operator = (const AbstractFX& other);
};